\chapter{Hyperscan正则库应用案例}
本章根据\ref{intro-sec-regex-cases}节中整数有效性判断、电话号码有效性判断、
整数重复数字判断、找最亲近同学、比压牌和牌型分类6典型应用案例的需求，
使用Intel Hyperscan正则库实现了正则表达式的编程。

\section{整数范围判断}
正整数字符串有效性判断的实现如代码\ref{code-int-range-hs}所示。

\cvfile[label=code-int-range-hs]{Hyperscan正则判断正整数范围有效性}
  {intel-Hyperscan/codes/int-range/int-range-hs.c}

在代码\ref{code-int-range-hs}中，\cinline{main()}函数的第17行声明了状态标志%
\cinline{flag}变量，并在第22行将该变量的地址传入\cinline{is_valid_int()}函数。
在\cinline{is_valid_int()}函数中，第64行又将该地址传入\cinline{hs_scan()}扫描
函数。该地址会在触发\cinline{on_match}指向的回调函数调用时，被传入回调函数。
在\cinline{on_match()}回调函数中，第80行将传入的\cinline{void*}指针强制转换为%
\cinline{int*}指针，然后在第82行，通过该指针修改其指向的\cinline{main()}函数中
的\cinline{flag}变量的值。

\section{电话号码判断}
城市电话号码有效性判断的实现如代码\ref{code-phonenum-hs}所示。

\cvfile[label=code-phonenum-hs]{Hyperscan正则判断电话号码字符串有效性}
{intel-Hyperscan/codes/phonenum/phonenum-check-hs.c}

对电话号码判断结果的处理与代码\ref{code-int-range-hs}类似，也是通过将状态标志%
\cinline{flag}变量的地址传入\cinline{check_phone_num()}函数(第25行)。
然后再传入\cinline{hs_scan()}扫描函数(第69行)。再在\cinline{on_match()}回调函数
中，通过指针强制转换后赋值以记录匹配状态(第86行和第88行)。

\section{判断重复数字}
判断整数中的重复数字的实现如代码\ref{code-repetition-hs}所示。

\cvfile[label=code-repetition-hs]{Hyperscan正则判断并显示重复数字}
  {intel-Hyperscan/codes/repetitionnum/repetition-numb-hs.c}

在代码\ref{code-repetition-hs}中，第7行---第12行定义了用于记录当前匹配状态的
结构体。第15---18行定义了用于记录Hyperscan正则表达式编译结果和临时存储空间
指针的结构体。用23行的\cinline{hs_prepare_scan()}函数对功能进行了封装。

在\cinline{print_repetition()}函数中，第105行将正整数转换为字符串，第106行对该
字符串进行了排序(如未进行排序，则无法进行正确匹配)。第108-110行对记录结果状态
的结构体变量\cinline{st}的各个成员进行初始化。将在第112行通过\cinline{&st}将其
地址传入\cinline{hs_scan()}扫描函数。该地址会在触发\cinline{on_match}指向的回调
函数调用时，被传入回调函数。

在\cinline{on_match()}回调函数中，第143行将传入的\cinline{void*}指针强制转换为%
\cinline{status_t *}指针，然后在第145行通过该指针将匹配状态写入结构体的%
\cinline{flag}成员，在第146---151行通过与前一次状态的比较以确定是否输出当前匹配
字符。

\begin{note}
  \begin{enumerate}
    \item Hyperscan不支持正则表达式中的反向引用，因此，需要构造能够匹配所有情况的
        正则表达式(第37---38行)。
    \item Hyperscan采用\enquote{全量匹配}，因此类似\cinline{"222"}的字符串%
        与正则表达式\cinline{"2{2,}"} 产生\cinline{"22"}和\cinline{"222"}两次匹配，
        这与该题意不符，因此，通过第146---151行进行了判断分析。
  \end{enumerate}
\end{note}

\section{寻找亲近同学}
寻找亲近同学的实现的实现如代码\ref{code-findclosest-hs}所示。

\cvfile[label=code-findclosest-hs]{Hyperscan正则寻找亲近同学}
  {intel-Hyperscan/codes/findclosest/findclosest-hs.c}

在代码\ref{code-findclosest-hs}中，第9---13行字义了用于记录最亲近同学信息的
结构体。在\cinline{main()}函数中，第29行声明了亲近同学结构体变量，并对其进行
了必要初始化，在第37行将该变量的地址传入函数\cinline{find_closest_classmate}。%
在\cinline{find_closest_classmate}函数中，第88行又将该地址传入%
\cinline{hs_scan()}扫描函数。该地址会在触发\cinline{on_match}指向的回调函数
调用时，被传入回调函数。在\cinline{on_match()}回调函数中，第127行将传入的%
\cinline{void*}指针强制转换为\cinline{closest_t *}指针，然后在第130---134行
实现了对匹配信息的记录。

\section{比压牌}
比压牌的实现如代码\ref{code-judgepoker-hs}所示。

\cvfile[label=code-judgepoker-hs]{Hyperscan正则判断比压牌}
  {intel-Hyperscan/codes/judgepoker/judgepoker-hs.c}

在代码\ref{code-judgepoker-hs}中，第55行声明了状态标志变量\cinline{flag}%
第93行通过\cinline{&flag}取得\cinline{flag}的地址传入\cinline{hs_scan()}%
扫描函数。该地址会在触发\cinline{on_match}指向的回调函数
调用时，被传入回调函数。在\cinline{on_match()}回调函数中，第113行将传入的%
\cinline{void*}指针强制转换为\cinline{int *}指针，然后在第115行通过该指针
对其指向的\cinline{flag}进行赋值，以记录匹配状态。

\section{牌型分类}
牌型分类的实现如代码\ref{code-classifypoker-hs}所示。

\cvfile[label=code-classifypoker-hs]{Hyperscan正则牌型分类}{
  intel-Hyperscan/codes/classify-poker-5cards/classify-poker-5cards-hs.c}

在代码\ref{code-classifypoker-hs}中，第7---32行定义了正则表达式全局数组，
第34---35行定义了分类结果字符串数组。第39---42行定义了用于记录Hyperscan正则
表达式编译结果和临时存储空间指针的结构体。用53行的\cinline{hs_prepare_scan()}%
函数对功能进行了封装。

在\cinline{classify_poker()}函数中，第143行声明了状态标志变量\cinline{flag}%
第148---149行通过\cinline{&flag}取得\cinline{flag}的地址传入\cinline{hs_scan()}%
扫描函数。该地址会在触发\cinline{on_match}指向的回调函数调用时，被传入回调函数。
在\cinline{on_match()}回调函数中，第132行将传入的\cinline{void*}指针强制转换为%
\cinline{int *}指针，然后在第133行通过该指针对其指向的\cinline{flag}进行赋值，
以记录匹配状态。

\begin{note}
  Hyperscan不支持正则表达式中的反向引用，因此，需要构造能够匹配所有情况的
  正则表达式(第7---32行)。
\end{note}
